package com.ykh.mybbsdemo.service.Impl;

import com.alibaba.fastjson.JSON;
import com.ykh.mybbsdemo.dao.mapper.SysUserMapper;
import com.ykh.mybbsdemo.dao.pojo.po.SysUser;
import com.ykh.mybbsdemo.service.LoginService;
import com.ykh.mybbsdemo.service.SysUserService;
import com.ykh.mybbsdemo.util.JWTUtils;
import com.ykh.mybbsdemo.dao.pojo.vo.ErrorCode;
import com.ykh.mybbsdemo.dao.pojo.vo.Result;
import com.ykh.mybbsdemo.dao.pojo.dto.LoginParam;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: YKH
 * Date: 2022-08-30
 * Time: 21:41
 */
@Service
@Transactional //开启事务
public class LoginServiceImpl implements LoginService {

    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Autowired
    private SysUserMapper sysUserMapper;

    //redis的对象
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    public static final String salt = "mszlu!!@#";

    /**
     * 登录
     * @param loginParam
     * @return
     */
    @Override
    public Result login(LoginParam loginParam) {
        /**
         * 1. 检查参数是否合法
         * 2. 根据用户名和密码去user表中查询 是否存在
         * 3. 如果不存在登录失败
         * 4. 如果存在,使用jwt 生成 token 返回给前端
         * 5. token放入 redis中, redis 映射存储 token 和 user信息的对应关系 设置过期时间
         *   ( 登录认证的时候 先认证token 字符串是否合法,去redis认证是否存在)
         */
        String account = loginParam.getAccount();
        String password = loginParam.getPassword();

        //1. 检查参数是否合法
        if(StringUtils.isBlank(account) || StringUtils.isBlank(password)) {
            //不合法返回错误码
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(),ErrorCode.PARAMS_ERROR.getMsg());
        }

        //密码的加密信息处理
        password = DigestUtils.md5Hex(password + salt);
        System.out.println("===============");
        System.out.println(password);

        //2. 检查用户是否存在
        SysUser sysUser = sysUserService.findUser(account,password);
        if( sysUser == null) {
            //3.用户不存在 , 返回错误码
            return Result.fail(ErrorCode.ACCOUNT_PWD_NOT_EXIST.getCode(),ErrorCode.ACCOUNT_PWD_NOT_EXIST.getMsg());
        }

        //4.使用jwt 生成 token 返回给前端
        String token = JWTUtils.createToken(sysUser.getId());

        //5.token放入 redis中, redis 映射存储 token 和 user信息的对应关系 设置过期时间
        redisTemplate.opsForValue().set("Token_" + token, JSON.toJSONString(sysUser),1,TimeUnit.DAYS);

        return Result.success(token);

    }

    /**
     * 校验token
     * @param token
     * @return
     */
    @Override
    public SysUser checkToken(String token) {
        //1. 判断token是否合法
        if (StringUtils.isBlank(token)) {
            //不合法返回空
            return null;
        }
        //解析token
        Map<String, Object> stringObjectMap = JWTUtils.checkToken(token);

        //2.解析失败为null ,返回null
        if( stringObjectMap == null) {
            return null;
        }

        //解析成功,在redis中再查询验证
        String userJson = redisTemplate.opsForValue().get("Token_" + token);

        //判断 userJosn 是否为空,为空就是token过期了
        if( StringUtils.isBlank(userJson)) {
            return null;
        }

        //到这里, 说明校验通过
        SysUser sysUser = JSON.parseObject(userJson,SysUser.class);
        SysUser sysUser1 = sysUserMapper.selectById(sysUser.getId());
        System.out.println(sysUser1.toString());
        return sysUser1;
    }

    //退出登录
    @Override
    public Result logout(String token) {
        redisTemplate.delete("Token_" + token);
        return Result.success(null);
    }

    //注册
    @Override
    public Result register(LoginParam loginParam) {
        /**
         * 1.判断是否合法
         * 2.判断账户是否存在,存在返回账户已经被注册
         * 3.不存在, 注册用户
         * 4.生成token
         * 5. 存入redis,并返回
         * 6. 注意加上事务, 一旦中间任何过程出现问题,需要回滚
         */
        //1.判断是否合法
        String account = loginParam.getAccount();
        String password = loginParam.getPassword();
        String nickname = loginParam.getNickname();
        if (StringUtils.isBlank(account)
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(nickname)
        ){
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(),ErrorCode.PARAMS_ERROR.getMsg());
        }
        //2.判断账户是否存在
        SysUser sysUser = this.sysUserService.findUserByAccount(account);
        if (sysUser != null){
            return Result.fail(ErrorCode.ACCOUNT_EXIST.getCode(),ErrorCode.ACCOUNT_EXIST.getMsg());
        }
        //3.进行注册用户
        sysUser = new SysUser();
        sysUser.setNickname(nickname);
        sysUser.setAccount(account);
        sysUser.setPassword(DigestUtils.md5Hex(password+salt));
        sysUser.setCreateDate(LocalDateTime.now());
        sysUser.setLastLogin(LocalDateTime.now());
        sysUser.setAvatar("/static/img/logo.b3a48c0.png");
        sysUser.setAdmin(1); //1 为true
        sysUser.setDeleted(0); // 0 为false
        sysUser.setSalt("");
        sysUser.setStatus("");
        sysUser.setEmail("");
        //保存新注册的账户到数据库
        this.sysUserService.save(sysUser);

        //token
        String token = JWTUtils.createToken(sysUser.getId());
        //将生成的token放到redis中
        redisTemplate.opsForValue().set("Token_"+token, JSON.toJSONString(sysUser),1, TimeUnit.DAYS);
        return Result.success(token);

    }
}
